// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rainbowchat.im.impl;

import com.eva.framework.dbpool.DBDepend;
import com.eva.framework.utils.LoggerFactory;
import com.x52im.rainbowchat.http.logic.LogicProcessor2;
import com.x52im.rainbowchat.im.ChatServerEventListener;
import com.x52im.rainbowchat.im.concurrent.CommonConcurrentExecutor;
import com.x52im.rainbowchat.im.dto.ChatType;
import com.x52im.rainbowchat.im.dto.MsgBody4Group;
import com.x52im.rainbowchat.im.dto.MsgBodyRoot;
import com.x52im.rainbowchat.im.dto.MsgType;
import com.x52im.rainbowchat.im.dto.RevokedMeta;

/**
 * 用户聊天消息记录（收集）管理器.
 * 
 * <p>
 * <b>用户聊天消息在什么地方收集合适？</b><br><br>
 * 详见“RainbowChat_pro_v4关键设计思路备忘.txt”。
 * 
 * @author Jack Jiang(http://www.52im.net/space-uid-1.html)
 * @since 2.5
 */
// TODO 优化建议：不要逐条都提交到数据库，比如可以当到了100条才一次性update到数据库哦（这个逻辑需要注意边界问题，比如非正常关闭等）。
public class MessageRecordManager// UserMsgCollectHelper.java
{
	/**
	 * 异步插入正常聊天记录到数据库中（当要仅处理正常聊天消息时，请使用本方法）。
	 * <p>
	 * <b>注意：</b>本方法仅用于正常的好友聊天、陌生人聊天、群聊天消息处理，不
	 * 支持群聊指令等消息体对象不是 {@link MsgBodyRoot}子类的情况下）。
	 * 
	 * @param originalDataContent 原始消息内容，即此条消息对应的Protocal协议包的dataContent内容
	 * @param fingerprint 消息指纹码（即消息唯一id）
	 * @see #colectMsgAsync(String, String, int, String, String, String)
	 */
	public static void colectChattingMsgAsync( final String originalDataContent, final String fingerprint)
	{
		if(originalDataContent != null)
		{
			// 解析原始的聊天数据（该数据是所有聊天消息的DTO对象的JSON文本）
			MsgBodyRoot tm = MsgBodyRoot.parseFromSender(originalDataContent);
			
			// 如果是群聊消息则取出parentFp值（即父消息指纹码，此指纹码当前主要用于消息撤回功能逻辑中）
			String parentFp = null;
			if(tm.getCy() == ChatType.CHAT_TYPE_GROUP$CHAT) {
				MsgBody4Group tmGroup = MsgBody4Group.parseFromSender(originalDataContent);
				parentFp = tmGroup.getParentFp();
			}
			
			if(tm != null && tm.getF() != null) {
				colectMsgAsync(tm.getF(), tm.getT(), tm.getCy(), String.valueOf(tm.getTy()), tm.getM(), fingerprint, parentFp);
			}
		}
	}
	
	/**
	 * 异步插入正常聊天记录、指令等数据到数据库中（当不需要区分是不是正常聊天消息时，可使用本方法）。
	 * <p>
	 * 本方法是通用方法，只要是符合聊天记录数据模型的字段定义即可，不一定非得是正常聊天消息内容。
	 * 
	 * @param src_uid
	 * @param dest_uid
	 * @param chat_type 聊天模式，详见：{@link MsgBodyRoot}中的常量定义
	 * @param msg_type
	 * @param msg_content
	 * @param fingerprint
	 * @parent parent_fp 本字段只有在聊天模式类型chatType为“2 群聊”时有意义，表示群聊消息扩散写前原始消息的指纹码（目前主要用于消息“撤回”功能时）
	 */
	public static void colectMsgAsync(final String src_uid, final String dest_uid
			, final int chat_type, final String msg_type, final String msg_content, final String fingerprint, String parent_fp)
	{
		// 将处理放在独立的线程池中处理以提升处理效率，防止在大用户量时阻塞其它服务
		CommonConcurrentExecutor.getInstance().execute(new Runnable(){
			@Override
			public void run()
			{
				MessageRecordManager.colectMsg(src_uid, dest_uid, chat_type, msg_type, msg_content, fingerprint, parent_fp);
			}
		});
	}
	
	private static void colectMsg(String src_uid, String dest_uid
			, int chat_type, String msg_type, String msg_content, String fingerprint, String parent_fp)
	{
		try{
			// 如果是撤回指令，则不应该直接插入聊天记录，而应该对本来被“撤回”的消息进行处理，否则将导致web产品中聊天记录的不正确
			if(msg_type.equals(String.valueOf(MsgType.TYPE_REVOKE))) {
				
				RevokedMeta rm = RevokedMeta.fromJSON(msg_content);
				String fpForMessage = rm.getFpForMessage();
				
				// 更新聊天记录
				LogicProcessor2.db.update(
						"UPDATE missu_user_msgs_collect set msg_type=?,msg_content=? where "+(chat_type == ChatType.CHAT_TYPE_GROUP$CHAT?"parent_fp=?":"fingerprint=?")
						, new Object[] {msg_type, msg_content, fpForMessage}
						, false);
				
//				// 更新聊天记录（存档） // TODO: 如在乎性能，则请注释掉存档记录的更新！
//				LogicProcessor2.db.update(
//						"UPDATE missu_user_msgs_collect_archived set msg_type=?,msg_content=? where "+(chat_type == ChatType.CHAT_TYPE_GROUP$CHAT?"parent_fp=?":"fingerprint=?")
//						, new Object[] {msg_type, msg_content, fpForMessage}
//						, false);
			}
			else {
				LogicProcessor2.db.update(
					"INSERT INTO missu_user_msgs_collect(src_uid,dest_uid,chat_type,msg_type,msg_content,online_count,msg_time, msg_time2,fingerprint, parent_fp)" +
							" VALUES(?,?,?,?,?,?,"+DBDepend.getDefaultDatetimeFunc()+","+System.currentTimeMillis()+",?,?)"
					, new Object[]{src_uid, dest_uid, chat_type, msg_type, msg_content
							// 当前在线用户数
							, ChatServerEventListener.getInstance().getLiverUsersMgr().getLiveUsers().size()
							, fingerprint, parent_fp}
					, false);
			}
		}
		catch (Exception e){
			LoggerFactory.getLog().error(MessageRecordManager.class.getSimpleName(), e);
		}
	}
}
